//
//  WxLogin.swift
//  imprint
//
//  Created by 小柠檬🍋 on 2025/1/11.
//

import Foundation
import SwiftUI
import LeanCloud
//注意。swift的特殊，  同一个字段的多个查询，需要用and连接
import GRDB

class CloudDiaryImpl : DiaryProtocol {
    //单位是毫秒
    func queryHomeDiary(userId: String, startTime: Int64, endTime: Int64, keyword: String?, pageNo: Int, pageSize: Int) async throws -> [DiaryBean] {
        let query1 = LCQuery(className: "Diary")
        query1.whereKey("userId", .equalTo(userId))
        
        let query2 = LCQuery(className: "Diary")
        query2.whereKey("roleType", .equalTo(IRoleType.USER.rawValue))
        
        let query3 = LCQuery(className: "Diary")
        query3.whereKey("content", .matchedSubstring(keyword ?? ""))
        
        //time <= endTime
        let query4 = LCQuery(className: "Diary")
        query4.whereKey("time", .lessThanOrEqualTo(endTime))
        
        //time >= startTime
        let query5 = LCQuery(className: "Diary")
        query5.whereKey("time", .greaterThanOrEqualTo(startTime))
        
        let query = try query1.and(query2).and(query3).and(query4).and(query5)
        query.whereKey("time", .descending) //降序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
    }
    
    
    func queryDiaryAi(userId:String, roleId:String, keyword:String?, pageNo:Int, pageSize:Int) async throws -> [DiaryBean] {
        let query = LCQuery(className: "Diary")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("roleId", .equalTo(roleId))
        query.whereKey("roleType", .equalTo(IRoleType.BOT.rawValue))
        if (keyword?.isEmpty ?? true) == false {
            query.whereKey("content", .matchedSubstring(keyword ?? ""))
        }
        query.whereKey("time", .descending) //降序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
    }
    
    //单位是毫秒
    func queryStatisticsDiary(userId: String, curTime: TimeInterval, endTime: TimeInterval, isPicture: Bool) async throws -> [DiaryBean] {
        let query1 = LCQuery(className: "Diary")
        let query2 = LCQuery(className: "Diary")
        let query3 = LCQuery(className: "Diary")
        let query4 = LCQuery(className: "Diary")
        let query5 = LCQuery(className: "Diary")
        query1.whereKey("userId", .equalTo(userId))
        query2.whereKey("roleType", .equalTo(IRoleType.USER.rawValue))
        //time <= curTime
        query3.whereKey("time", .lessThanOrEqualTo(curTime))
        //time >= endTime
        query4.whereKey("time", .greaterThanOrEqualTo(endTime))
        let query = try query1.and(query2).and(query3).and(query4).and(query5)
        query.whereKey("time", .descending) //降序
        query.limit = 300
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
    }
    
    func queryDiaryLately(userId: String, pageNo: Int, pageSize: Int) async throws -> [DiaryBean] {
        let query = LCQuery(className: "Diary")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("roleType", .equalTo(IRoleType.USER.rawValue))
        query.whereKey("createdAt", .descending) //按照创建时间来
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
    }
    
    func queryDiaryUpdateAll(userId: String, pageNo: Int, pageSize: Int) async throws -> [DiaryBean] {
        let query = LCQuery(className: "Diary")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("updatedAt", .descending) //按照创建时间来
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
    }
    
    func queryTag(userId: String, tagId: String?, pageNo: Int, pageSize: Int) async throws -> [DiaryBean] {
        let query = LCQuery(className: "Diary")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("roleType", .equalTo(IRoleType.USER.rawValue))
        query.whereKey("tagId", .equalTo(tagId ?? ""))
        query.whereKey("time", .descending) //降序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
    }
    
    func queryMemoryDiary(aiUserId: String?, userId: String, pageNo: Int, pageSize: Int) async throws -> [DiaryBean] {
        if (aiUserId ?? "")?.isEmpty == true {
            //我的未提取日记
            let query = LCQuery(className: "Diary")
            query.whereKey("userId", .equalTo(userId))
            query.whereKey("roleType", .equalTo(IRoleType.USER.rawValue))
            query.whereKey("memory", .notEqualTo(true))
            query.whereKey("time", .descending) //降序
            query.limit = pageSize
            query.skip = pageNo * pageSize
            return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
        } else {
            //ai未提取日记
            let query = LCQuery(className: "Diary")
            query.whereKey("roleId", .equalTo(aiUserId ?? ""))
            query.whereKey("userId", .equalTo(userId))
            query.whereKey("roleType", .equalTo(IRoleType.BOT.rawValue))
            query.whereKey("memory", .notEqualTo(true))
            query.whereKey("time", .descending) //降序
            query.limit = pageSize
            query.skip = pageNo * pageSize
            return try await LeancloudManager.instance.getList(query: query, modeType: DiaryBean.self)
        }
    }
    
    func saveDiary(bean: DiaryBean) async throws -> Void {
        try check(userManager.isLogin(), "当前是官方备份，请先登录账号才可写日记")
        if (bean.userId ?? "").isEmpty {
            bean.userId = userManager.getUserId()
        }
        
        let id = try await LeancloudManager.instance.saveToId(todo: bean)
        bean.objectId = id
    }
    
    func delDiary(bean: DiaryBean) async throws {
        try await LeancloudManager.instance.del(todo: bean)
    }
    
    func saveCloudPicture(bean: CloudPictureBean) async throws {
        try check(userManager.isLogin(), "当前是官方备份，请先登录账号才可写日记")
        if (bean.userId ?? "").isEmpty {
            bean.userId = userManager.getUserId()
        }
        
        let id = try await LeancloudManager.instance.saveToId(todo: bean)
        bean.objectId = id
    }
    
    func delCloudPicture(bean: CloudPictureBean) async throws {
        try await LeancloudManager.instance.del(todo: bean)
    }
    
    func queryPicture(diaryId: String, userId: String, limit: Int) async throws -> [CloudPictureBean] {
        let query = LCQuery(className: "CloudPicture")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("diaryId", .equalTo(diaryId))
        if limit > 0 {
            query.limit = limit
        }
        query.whereKey("sort", .ascending) //生序
        return try await LeancloudManager.instance.getList(query: query, modeType: CloudPictureBean.self)
    }
    
    func queryDiaryComment(diaryId: String, pageNo: Int, pageSize: Int) async throws -> [DiaryCommentBean] {
        let query = LCQuery(className: "DiaryComment")
        query.whereKey("userId", .equalTo(userManager.getUserId()))
        query.whereKey("diaryId", .equalTo(diaryId))
        query.whereKey("time", .ascending) //生序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryCommentBean.self)
    }
    
    func queryDiaryComment(diaryId: String, aiRoleId: String, pageNo: Int, pageSize: Int) async throws -> [DiaryCommentBean] {
        let query = LCQuery(className: "DiaryComment")
        query.whereKey("userId", .equalTo(userManager.getUserId()))
        query.whereKey("diaryId", .equalTo(diaryId))
        query.whereKey("roleId", .equalTo(aiRoleId))
        query.whereKey("time", .ascending) //生序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: DiaryCommentBean.self)
    }
    
    func queryDiaryLast(diaryId: String,aiRoleId: String)  async throws -> DiaryCommentBean? {
        let query = LCQuery(className: "DiaryComment")
        query.whereKey("userId", .equalTo(userManager.getUserId()))
        query.whereKey("diaryId", .equalTo(diaryId))
        query.whereKey("time", .descending) //降序
        query.limit = 1
        query.skip = 0
        return try await LeancloudManager.instance.getFirst(query: query, modeType: DiaryCommentBean.self)
    }
    
    func addDiaryComment(bean: DiaryCommentBean) async throws -> DiaryCommentBean? {
        try check(userManager.isLogin(), "当前是官方备份，请先登录账号才可使用")
        bean.userId = userManager.getUserId()
        let id = try await LeancloudManager.instance.saveToId(todo: bean)
        bean.objectId = id
        return bean
    }
    
    func deleteDiaryComment(bean: DiaryCommentBean) async throws {
        try await LeancloudManager.instance.del(todo: bean)
    }
    
    func queryWeekLetter(userId: String, pageNo: Int, pageSize: Int) async throws -> [WeeklyLetterBean] {
        let query = LCQuery(className: "WeeklyLetter")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("time", .descending) //生序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: WeeklyLetterBean.self)
    }
    
    func updateLastWeekLetter(bean: WeeklyLetterBean) async throws -> WeeklyLetterBean {
        let id = try await LeancloudManager.instance.saveToId(todo: bean)
        bean.objectId = id
        return bean
    }
    
    func deleteLastWeekLetter(bean: WeeklyLetterBean) async throws {
        try await LeancloudManager.instance.del(todo: bean)
    }
    
    func queryActiveCall(userId: String, pageNo: Int, pageSize: Int) async throws -> [CallHistoryBean] {
        let query = LCQuery(className: "ActiveCall")
        query.whereKey("userId", .equalTo(userId))
        query.whereKey("time", .descending) //生序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: CallHistoryBean.self)
    }
    
    func deleteActiveCall(bean: CallHistoryBean) async throws {
        try await LeancloudManager.instance.del(todo: bean)
    }
    
    func updateActiveCall(bean: CallHistoryBean) async throws {
        try await LeancloudManager.instance.save(todo: bean)
    }
    
    func existTask(timeKey: String, roleId: String?, userId: String, type: Int) async throws -> Bool {
        let query = LCQuery(className: "task")
        query.whereKey("userId", .equalTo(userId))
        if let roleId = roleId {
            query.whereKey("roleId", .equalTo(roleId))
        }
        query.whereKey("timeKey", .equalTo(timeKey))
        query.whereKey("type", .equalTo(type))
        let bean = try await LeancloudManager.instance.getFirst(query: query, modeType: TaskBean.self)
        return bean != nil
    }
    
    func saveTask(bean: TaskBean) async throws -> TaskBean? {
        try check(userManager.isLogin(), "当前是官方备份，请先登录账号才可写日记")
        let id =  try await LeancloudManager.instance.saveToId(todo: bean)
        bean.objectId = id
        return bean
    }
    func getLatelyTask(roleId: String?, userId: String, type: Int, pageSize: Int) async throws -> [TaskBean] {
        let query = LCQuery(className: "task")
        query.whereKey("userId", .equalTo(userId))
        if let roleId = roleId {
            query.whereKey("roleId", .equalTo(roleId))
        }
        query.whereKey("type", .equalTo(type))
        query.whereKey("execute", .equalTo(false)) //获取未执行任务
        let curTime = Date().timeIntervalSince1970
        //time <= curTime
        query.whereKey("time", .lessThanOrEqualTo(getMillisecond(curTime)))
        query.whereKey("time", .descending) //升序
        query.limit = pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: TaskBean.self)
    }
    
    func getUnExecutedTask(roleId: String?, userId: String, type: Int?) async throws -> [TaskBean] {
        let query = LCQuery(className: "task")
        query.whereKey("userId", .equalTo(userId))
        if let roleId = roleId {
            query.whereKey("roleId", .equalTo(roleId))
        }
        if let type = type {
            query.whereKey("type", .equalTo(type))
        }
        query.whereKey("execute", .equalTo(false)) //获取未执行任务
        query.whereKey("time", .descending) //升序
        return try await LeancloudManager.instance.getList(query: query, modeType: TaskBean.self)
    }
    
    func deleteTask(bean: TaskBean) async throws {
        try await LeancloudManager.instance.del(todo: bean)
    }
    
    func queryChat(objectId: String) async throws -> ChatBean? {
        return try await DatabaseManager.shared.dbQueue.read { db in
            let list = try ChatBean
                .filter(Column("objectId") == objectId)
                .limit(1)
                .order(Column("time").desc)
                .fetchAll(db)
            if list.isEmpty {
                return nil
            } else {
                return list[0]
            }
        }
    }
    
    
    func queryChat(pageNo: Int, pageSize: Int) async throws -> [ChatBean] {
        return try await DatabaseManager.shared.dbQueue.read { db in
            try ChatBean
                .filter(Column("status") == IStatusType.NORMAL.rawValue)
                .limit(pageSize, offset: pageNo * pageSize)
                .order(Column("time").desc)
                .fetchAll(db)
        }
    }
    
    func queryChat(aiUserId: String, userId: String, pageNo: Int, pageSize: Int) async throws -> [ChatBean] {
        return try await DatabaseManager.shared.dbQueue.read { db in
            try ChatBean
                .filter(Column("status") == IStatusType.NORMAL.rawValue)
                .filter(Column("aiUserId") == aiUserId)
                .filter(Column("userId") == userId)
                .limit(pageSize, offset: pageNo * pageSize)
                .order(Column("time").desc)
                .fetchAll(db)
        }
    }
    
    func queryChat(aiUserId: String, userId: String, isRefresh: Bool, timestamp: Int64, pageSize: Int) async throws -> [ChatBean] {
        return try await DatabaseManager.shared.dbQueue.read { db in
            try ChatBean
                .filter(Column("status") == IStatusType.NORMAL.rawValue)
                .filter(Column("aiUserId") == aiUserId)
                .filter(Column("userId") == userId)
            // 根据isRefresh决定时间筛选条件
                .filter(isRefresh ? Column("time") < timestamp : Column("time") > timestamp)
                .order(Column("time").desc)
                .limit(pageSize)
                .fetchAll(db)
        }
    }
    
    func queryNewChat(aiUserId: String, userId: String) async throws -> ChatBean? {
        let list =  try await queryChat(aiUserId: aiUserId, userId: userId, pageNo: 0, pageSize: 1)
        if list.isEmpty {
            return nil
        }
        let bean = list[0]
        return bean
    }
    
    func queryMemoryChat(aiUserId: String, userId: String, pageNo: Int, pageSize: Int) async throws -> [ChatBean] {
        return try await DatabaseManager.shared.dbQueue.read { db in
            try ChatBean
                .filter(Column("status") == IStatusType.NORMAL.rawValue)
                .filter(Column("aiUserId") == aiUserId)
                .filter(Column("userId") == userId)
                .filter(Column("memory") != 1 || Column("memory") == nil)
                .limit(pageSize, offset: pageNo * pageSize)
                .order(Column("time").desc)
                .fetchAll(db)
        }
    }
    
    func addChat(bean: ChatBean) async throws -> ChatBean {
        bean.modifySign = true
        bean.objectId = UUID().uuidString
        let time = Date().timeIntervalSince1970
        bean.createTime = getMillisecond(time)
        bean.updateTime = getMillisecond(time)
        try await DatabaseManager.shared.dbQueue.write { db in
            try bean.insert(db)
        }
        return bean
    }
    
    func saveChat(bean: ChatBean) async throws {
        try await DatabaseManager.shared.dbQueue.write { db in
            try bean.update(db)
        }
    }
    
    func saveChat(list: [ChatBean]) async throws {
        try await DatabaseManager.shared.dbQueue.write { db in
            try list.forEach {
                try $0.update(db)
            }
        }
    }
    
    func clearChat(aiUserId: String, userId: String) async throws {
        try await DatabaseManager.shared.dbQueue.write { db in
            try ChatBean
                .filter(Column("aiUserId") == aiUserId)
                .filter(Column("userId") == userId)
                .deleteAll(db)
        }
    }
    
    func deleteChat(bean: ChatBean) async throws {
        try await DatabaseManager.shared.dbQueue.write { db in
            try ChatBean
                .filter(Column("objectId") == bean.objectId)
                .deleteAll(db)
        }
    }
    
    func deleteChatList(beans: [ChatBean]) async throws {
        let objectIds = beans.map { $0.objectId }

          try await DatabaseManager.shared.dbQueue.write { db in
              try ChatBean
                  .filter(objectIds.contains(Column("objectId")))
                  .deleteAll(db)
          }
    }
    
    func getEmojiPictureList() async throws -> [EmojiPictureBean] {
        return try await DatabaseManager.shared.dbQueue.read { db in
            try EmojiPictureBean
                .filter(Column("text") != nil)
                .filter(Column("text") != "")
                .order(Column("sort").asc)
                .fetchAll(db)
        }
    }
    
    func addEmojiPicture(bean: EmojiPictureBean) async throws -> EmojiPictureBean {
        bean.objectId = UUID().uuidString
        try await DatabaseManager.shared.dbQueue.write { db in
            try bean.insert(db)
        }
        return bean
    }
    
    func saveEmojiPicture(bean: EmojiPictureBean) async throws {
        try await DatabaseManager.shared.dbQueue.write { db in
            try bean.update(db)
        }
    }
    
    func deleteEmojiPicture(bean: EmojiPictureBean) async throws {
        try await DatabaseManager.shared.dbQueue.write { db in
            try EmojiPictureBean
                .filter(Column("objectId") == bean.objectId)
                .deleteAll(db)
        }
    }
    
    func queryNewChatMemory(aiRoleId: String, userId: String) async throws -> [AiMemoryBean] {
        let pageNo = 0
        let pageSize = 50
        let query = LCQuery(className: "AiMemory")
        query.whereKey("userId", .equalTo(userId))
        if aiRoleId.isEmpty == false {
            query.whereKey("aiRoleId", .equalTo(aiRoleId))
        }
        query.whereKey("roleType", .equalTo(IRoleType.BOT.rawValue))
        query.whereKey("status", .equalTo(IStatusType.NORMAL.rawValue))

        query.whereKey("createdAt", .descending) //降序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: AiMemoryBean.self)
    }
    
    func queryMyNewChatMemory(userId: String) async throws -> [AiMemoryBean] {
        let pageNo = 0
        let pageSize = 50
        let query = LCQuery(className: "AiMemory")
        query.whereKey("userId", .equalTo(userId))
    
        query.whereKey("roleType", .equalTo(IRoleType.USER.rawValue))
        query.whereKey("status", .equalTo(IStatusType.NORMAL.rawValue))

        query.whereKey("createdAt", .descending) //降序
        query.limit = pageSize
        query.skip = pageNo * pageSize
        return try await LeancloudManager.instance.getList(query: query, modeType: AiMemoryBean.self)
    }
    
    func addMemory(bean: AiMemoryBean) async throws {
        try check(userManager.isLogin(), "当前是官方备份，请先登录账号才可写日记")
        try await LeancloudManager.instance.save(todo: bean)
    }
}
